package pCloud;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import pCloud.obligation.ApproximationObligation;
import pCloud.obligation.DataProcessingObligation;
import pCloud.obligation.SlidingWindowObligation;

import com.sun.xacml.Indenter;
import com.sun.xacml.Obligation;
import com.sun.xacml.ParsingException;
import com.sun.xacml.attr.AttributeValue;
import com.sun.xacml.attr.IntegerAttribute;
import com.sun.xacml.attr.StringAttribute;
import com.sun.xacml.ctx.Attribute;
import com.sun.xacml.ctx.RequestCtx;
import com.sun.xacml.ctx.ResponseCtx;
import com.sun.xacml.ctx.Result;

/**
 * Take a
 * 
 * @author anhdinh
 * 
 */
public class SimplePEP {

	static final String DEFAULT_RESOURCE_ID = SQLResourceConnection.DEFAULT_DATABASE;
	SimplePDP pdp;
	ResourceController resourceController;
	String tableId, databaseId, username, password, driver;
	ResourceConnection rc;

	public SimplePEP(SimplePDP pdp, String driver, String username,
			String password) {
		this.pdp = pdp;
		this.username = username;
		this.password = password;
		this.driver = driver;
		resourceController = new ResourceController();
	}

	public SimplePEPResponse evaluateRequest(String requestFile)
			throws Exception {
		pdp.setRequestCtx(requestFile);

		RequestCtx requestCtx = pdp.getRequestContext();

		ResponseCtx outputs = pdp.evaluate();

		Set results = outputs.getResults();

		java.util.Iterator it = results.iterator();
		Result result = null;
		while (it.hasNext()) {
			result = (Result) it.next();
			if (result.getDecision() != Result.DECISION_PERMIT) {
				System.out.println("Decision = "
						+ this.getDecision(result.getDecision()));
				return null;
			} else
				System.out.println("Decision = Permit");
		}

		// 1. Build an obligation map
		HashMap<URI, Obligation> obligationMap = this.getObligations(result);

		// 2. Open access to the database requested.
		this.openDatabaseConnection(requestCtx);

		if (obligationMap.containsKey(new URI(
				PCloudAttributeAndType.OBLIGATION_APPROXIMATION_PARAM))
				|| obligationMap.containsKey(new URI(
						PCloudAttributeAndType.OBLIGATION_APPROXIMATION_VALUE))) {
			ApproximationObligation ao = new ApproximationObligation();
			//ao.processObligation(rc, obligationMap, requestCtx, tableId,
			//		System.out);
			return null;
		} else if (obligationMap.containsKey(new URI(
				PCloudAttributeAndType.OBLIGATION_SLIDING_WINDOW_ID))) {
			SlidingWindowObligation swo = new SlidingWindowObligation();
//			swo.processObligation(rc, obligationMap, requestCtx, tableId,
//					System.out);
			return null;
		} else {
			// 2. For now, assume there's only simple data processing obligation
			DataProcessingObligation dpo = new DataProcessingObligation();
//			dpo.processObligation(rc, obligationMap, requestCtx, tableId,
//					System.out);
			return null;
		}

	}

	private void openDatabaseConnection(RequestCtx requestCtx) throws Exception {
		Set resourceAtts = requestCtx.getResource();
		ArrayList<AttributeValue> values = Utilities.getAttributeValue(
				PCloudAttributeAndType.RESOURCE_DATABASE_ID, resourceAtts);
		databaseId = Utilities.getDatabaseId(values);

		values = Utilities.getAttributeValue(
				PCloudAttributeAndType.RESOURCE_TABLE_ID, resourceAtts);
		tableId = Utilities.getTableId(values);
		rc = resourceController.createConnection(driver, databaseId,
				this.username, this.password, ResourceController.SQL_DATATYPE);

	}

	private HashMap<URI, Obligation> getObligations(Result result) {
		HashMap<URI, Obligation> obligationMap = new HashMap<URI, Obligation>();
		Iterator it = result.getObligations().iterator();
		Obligation ob;
		while (it.hasNext()) {
			ob = (Obligation) it.next();
			obligationMap.put(ob.getId(), ob);
		}
		return obligationMap;
	}

	protected String getDecision(int dec) {
		String res;
		if (dec == Result.DECISION_DENY)
			res = "Deny";
		else if (dec == Result.DECISION_INDETERMINATE)
			res = "Intermediate";
		else if (dec == Result.DECISION_NOT_APPLICABLE)
			res = "Not Applicable";
		else
			res = "Permit";
		return res;
	}

}

class SimplePEPResponse {
	String permission;
	Object data;

	public SimplePEPResponse(String perm, Object data) {
		this.permission = perm;
		this.data = data;
	}
}
